﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows;
using System.Windows.Media;

namespace Brjnk.GpxExplorer.UI
{
    public partial class CheckNewVersionWindow : Window, INotifyPropertyChanged
    {
        public CheckNewVersionWindow()
        {
            this.Loaded += new RoutedEventHandler(CheckNewVersionWindow_Loaded);
            InitializeComponent();
        }

        private SynchronizationContext context;

        private void CheckNewVersionWindow_Loaded(object sender, RoutedEventArgs e)
        {
            this.context = SynchronizationContext.Current;
            ThreadPool.QueueUserWorkItem(o => CheckNewVersion());
        }

        private void CheckNewVersion()
        {
            try
            {
                var html = DownloadInfo();
                ReadInfo(html);
            }
            catch
            {
                Invoke(() => this.Failed = true);
            }
            Invoke(() => this.InProgress = false);
        }

        //Group1:Group2="Group3"
        //Group1 - klíč
        //Group2 - včetně dvojtečky (nemá význam)
        //Group3 - argument
        //Group4 - hodnota
        private const string regex = @"([a-zA-Z0-9]+)(:([a-zA-Z0-9\._]+))*=""([^""]*)""";

        private void ReadInfo(string html)
        {
            Invoke(() => messages.Clear());
            var r = new System.Text.RegularExpressions.Regex(regex);
            var matches = r.Matches(html);
            bool ver = false; //slouží pro kontrolu, zda byla hodnota načtena
            foreach (Match match in matches)
            {
                if (match.Groups[1].Value == "LastVersion")
                { ProcessLastVersion(match.Groups[4].Value); ver = true; }
                else if (match.Groups[1].Value == "Message")
                    ProcessMessage(match.Groups[3].Value, match.Groups[4].Value);
            }
            if (!ver) Invoke(() => this.Failed = true);
        }

        private void ProcessLastVersion(string value)
        {
            var lastVersion = Version.Parse(value);
            var current = App.Instance.Workspace.VersionInfo.Version;
            if (lastVersion > current)
            {
                Invoke(() => this.NewVersionAvailable = true);
                Invoke(() => this.NewVersionUnavailable = false);
            }
            else
            {
                Invoke(() => this.NewVersionAvailable = false);
                Invoke(() => this.NewVersionUnavailable = true);
            }
            Invoke(() => this.NewerVersion = lastVersion.ToString());
        }

        private void ProcessMessage(string arg, string value)
        {
            Version ver;
            if (Version.TryParse(arg, out ver))
            {
                var current = App.Instance.Workspace.VersionInfo.Version;
                if (ver != current) return;
            }

            value = value.Replace("{NewLine}", Environment.NewLine);
            Color c;
            if (value.Contains("{Red}"))
            { c = Colors.Red; value = value.Replace("{Red}", string.Empty); }
            else if (value.Contains("{Green}"))
            { c = Colors.Green; value = value.Replace("{Green}", string.Empty); }
            else if (value.Contains("{Blue}"))
            { c = Colors.Blue; value = value.Replace("{Blue}", string.Empty); }
            else if (value.Contains("{Orange}"))
            { c = Colors.Orange; value = value.Replace("{Orange}", string.Empty); }
            else if (value.Contains("{Gold}"))
            { c = Colors.Gold; value = value.Replace("{Gold}", string.Empty); }
            else if (value.Contains("{Black}"))
            { c = Colors.Black; value = value.Replace("{Black}", string.Empty); }
            else c = Colors.Black;
            Invoke(() => this.Messages.Add(new Tuple<string, Brush>(value, new SolidColorBrush(c))));
        }

        private string DownloadInfo()
        {
            var wc = new System.Net.WebClient();
            wc.Encoding = System.Text.Encoding.UTF8;
            var html = wc.DownloadString(@"https://gpxexplorer.codeplex.com/wikipage?title=VersionCheck");
            html = System.Net.WebUtility.HtmlDecode(html);
            return html;
        }

        private void Invoke(Action action)
        {
            if (context == null) action();
            else context.Post(o => action(), null);
        }

        private bool inProgress = true;

        public bool InProgress
        {
            get { return inProgress; }
            set { inProgress = value; OnPropertyChanged("InProgress"); }
        }

        private bool newVersionAvailable;

        public bool NewVersionAvailable
        {
            get { return newVersionAvailable; }
            private set { newVersionAvailable = value; OnPropertyChanged("NewVersionAvailable"); }
        }

        private bool newVersionUnavailable;

        public bool NewVersionUnavailable
        {
            get { return newVersionUnavailable; }
            private set { newVersionUnavailable = value; OnPropertyChanged("NewVersionUnavailable"); }
        }

        private bool failed;

        public bool Failed
        {
            get { return failed; }
            private set { failed = value; OnPropertyChanged("Failed"); }
        }

        private string newerVersion;

        public string NewerVersion
        {
            get { return newerVersion; }
            private set { newerVersion = value; OnPropertyChanged("NewerVersion"); }
        }

        private ObservableCollection<Tuple<string, Brush>> messages = new ObservableCollection<Tuple<string, Brush>>();

        public ObservableCollection<Tuple<string, Brush>> Messages
        {
            get { return messages; }
            private set { messages = value; OnPropertyChanged("Messages"); }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
    }
}